package server;


import sensorBoard.ISensorBoardComponent;
import sensorBoard.io.Battery;
import sensorBoard.io.Flash;
import sensorBoard.io.IOManager;
import sensorBoard.io.LedOut;
import sensorBoard.io.SwitchInput;
import sensorBoard.sensor.AccelerometerSensor;
import sensorBoard.sensor.LightSensor;
import sensorBoard.sensor.SensorManager;
import sensorBoard.sensor.TemperatureSensor;
import server.interfaces.IDispatcher;
import server.interfaces.IMobileAgentCommunicationChannelReceiver;
import server.interfaces.IMobileAgentCommunicationChannelSender;
import server.interfaces.IMobileAgentExecutionEngine;
import server.interfaces.IMobileAgentMigrationManager;
import server.interfaces.IMobileAgentNaming;
import server.interfaces.IMobileAgentServer;
import server.interfaces.ISensorBoardManager;
import server.interfaces.ITimer;
import server.interfaces.ITimerManager;
import server.interfaces.InvalidCommunicationPortException;

import com.Event;

import agent.AgentProxy;
import agent.IAgentProxy;

public class Factory {
	
	/**
	 * ExecutionEngine
	 */
	private static IMobileAgentExecutionEngine executionEngine = null;
	/**
	 * MigrationManager
	 */
	private static IMobileAgentMigrationManager migrationManager = null;
	/**
	 * CommunicationChannelSender
	 */
	private static IMobileAgentCommunicationChannelSender communicationChannelSender = null;
	/**
	 * CommunicationChannelReceiver
	 */
	private static IMobileAgentCommunicationChannelReceiver communicationChannelReceiver = null;
	/**
	 * Dispatcher
	 */
	private static IDispatcher dispatcher = null;	
	/**
	 * Naming
	 */
	private static IMobileAgentNaming naming = null;
	/**
	 * TimerManager
	 */
	private static ITimerManager timerManager = null;
	
	/**
	 * MobileAgentServer
	 */
	private static IMobileAgentServer mobileAgentServer = null;
	
	/**
	 * SensorManager
	 */
	private static ISensorBoardManager sensorManager = null;
	
	/**
	 * IOManager
	 */
	private static ISensorBoardManager ioManager = null;
	/**
	 * TemperatureSensor
	 */
	private static ISensorBoardComponent temperatureSensor = null;
	
	/**
	 * SwitchInput
	 */
	private static ISensorBoardComponent lightSensor = null;
	
	/**
	 * AccelerometerSensor
	 */
	private static ISensorBoardComponent acceleratorSensor = null;
	
	/**
	 * LedOut
	 */
	private static ISensorBoardComponent ledActuator = null;
	
	/**
	 * SwitchInput
	 */
	private static ISensorBoardComponent switchInput = null;
	
	/**
	 * FlashManager
	 */
	private static ISensorBoardComponent flashManager = null;
	
	/**
	 * BatteryManager
	 */
	private static ISensorBoardComponent batteryManager = null;
	
	/**
	 * Getter of the component IMobileAgentExecutionEngine
	 * @param communicationPort Datagram connection's port
	 * @return the component IMobileAgentExecutionEngine
	 */
	public static IMobileAgentExecutionEngine getIMobileAgentExecutionEngine (String communicationPort) {
		if (executionEngine  == null) {
			executionEngine = new MobileAgentExecutionEngine(communicationPort);		
		}
		
		return executionEngine;	
	}

	/**
	 * Getter of the component IMobileAgentMigrationManager
	 * @param executionEngine the component IMobileAgentExecutionEngine
	 * @return the component IMobileAgentMigrationManager
	 */
	public static IMobileAgentMigrationManager getIMobileAgentMigrationManager(IMobileAgentExecutionEngine executionEngine) {
		
		if (migrationManager == null) {
			migrationManager = new MobileAgentMigrationManager(executionEngine);
			new Thread(migrationManager).start();
		}
		
		return migrationManager;		
	}
	
	/**
	 * Getter of the component IMobileAgentCommunicationChannelSender
	 * @param executionEngine the component IMobileAgentExecutionEngine
	 * @param communicationPort Datagram connection's port
	 * @return the component IMobileAgentCommunicationChannelSender
	 */
	public static IMobileAgentCommunicationChannelSender getIMobileAgentCommunicationChannelSender(IMobileAgentExecutionEngine executionEngine, String communicationPort) {
		
		if (communicationChannelSender == null) {
			communicationChannelSender = new MobileAgentCommunicationChannelSender(executionEngine, communicationPort);
			new Thread(communicationChannelSender).start();
		}
		
		return communicationChannelSender;		
	}
	
	/**
	 * Getter of the component IMobileAgentCommunicationChannelReceiver
	 * @param executionEngine the component IMobileAgentExecutionEngine
	 * @param communicationChannelSender IMobileAgentCommunicationChannelSender component
	 * @param communicationPort Datagram connection's port 
	 * @return the component IMobileAgentCommunicationChannelReceiver
	 */
	public static IMobileAgentCommunicationChannelReceiver getIMobileAgentCommunicationChannelReceiver(IMobileAgentExecutionEngine executionEngine, IMobileAgentCommunicationChannelSender communicationChannelSender, String communicationPort) {
		
		if (communicationChannelReceiver == null) {
			communicationChannelReceiver = new MobileAgentCommunicationChannelReceiver(executionEngine, communicationChannelSender, communicationPort);
			new Thread(communicationChannelReceiver).start();
		}
		
		return communicationChannelReceiver;		
	}
	
	/**
	 * Getter of the component IDispatcher
	 * @param executionEngine the component IMobileAgentExecutionEngine
	 * @return the component IDispatcher
	 */
	public static IDispatcher getIDispatcher(IMobileAgentExecutionEngine executionEngine) {
		
		if (dispatcher  == null) {
			dispatcher = new Dispatcher(executionEngine);
			new Thread(dispatcher).start();
		}
		
		return dispatcher;		
	}	
	
	/**
	 * Getter of the component IMobileAgentNaming
	 * @param executionEngine the component IMobileAgentExecutionEngine
	 * @return the component IMobileAgentNaming
	 */
	public static IMobileAgentNaming getIMobileAgentNaming(IMobileAgentExecutionEngine executionEngine) {
		
		if (naming  == null) {
			naming = new MobileAgentNaming(executionEngine);			
		}
		
		return naming;		
	}	
	
	/**
	 * Getter of the component IAgentProxy
	 * @param agentID Agent ID
	 * @param agentAddress Agent address
	 * @return the component IAgentProxy
	 */
	public static IAgentProxy getIAgentProxy(String agentID, String agentAddress) {
		
		return new AgentProxy(agentID, agentAddress);
		
	}
	
	/**
	 * Getter of the component ITimerManager
	 * @param executionEngine the component IMobileAgentExecutionEngine
	 * @return the component ITimerManager
	 */
	public static ITimerManager getITimerManager(IMobileAgentExecutionEngine executionEngine) {
		if (timerManager == null) {
			timerManager = new TimerManager(executionEngine);
		}
		
		return timerManager;
			
	}
	
	/**
	 * Creates and starts a timer instance
	 * @param timerID Timer ID
	 * @param timerManager Timer Manager
	 * @param periodic if it's periodic or not
	 * @param timeout timeout's length in ms
	 * @param backEvent event to send at expiration time
	 * @return a timer instance
	 */
	public static ITimer getITimer (String timerID, ITimerManager timerManager, boolean periodic, long timeout, Event backEvent) {
		
		return new Timer(timerID, timerManager, periodic, timeout, backEvent);
	}
	
	/**
	 * Getter of the component IMobileAgentServer
	 * @param communicationPort Datagram connection's port
	 * @return the component IMobileAgentServer
	 * @throws InvalidCommunicationPortException if the port number is the same of the migration's port.
	 */
	public static IMobileAgentServer getIMobileAgentsServer (String communicationPort) throws InvalidCommunicationPortException {
		if (mobileAgentServer  == null) {
			mobileAgentServer = new MobileAgentServer(communicationPort);		
		}
		
		return mobileAgentServer;	
	}
	
	/**
	 * Getter of the component ISensorBoardManager
	 * @param executionEngine the component IMobileAgentExecutionEngine
	 * @return the component ISensorBoardManager
	 */
	public static ISensorBoardManager getSensorManager (IMobileAgentExecutionEngine executionEngine) {
		if (sensorManager == null) {
			sensorManager = new SensorManager(executionEngine);
			new Thread(sensorManager).start();
		}		
		return sensorManager;
	}
	
	/**
	 * Getter of the component IOManager
	 * @param executionEngine the component IMobileAgentExecutionEngine
	 * @return the component IOManager
	 */
	public static ISensorBoardManager getIOManager (IMobileAgentExecutionEngine executionEngine) {
		if (ioManager == null) {
			ioManager = new IOManager(executionEngine);
			new Thread(ioManager).start();
		}		
		return ioManager;
	}
	
	/**
	 * Getter of the component TemperatureSensor
	 * @param sensorBoardManager ISensorBoardManager component
	 * @return the component TemperatureSensor
	 */
	public static ISensorBoardComponent getTemperatureSensor(ISensorBoardManager sensorBoardManager) {
		if (temperatureSensor == null) {
			temperatureSensor = new TemperatureSensor(sensorBoardManager);
		}
		return temperatureSensor;
		
	}

	/**
	 * Getter of the component LightSensor
	 * @param sensorBoardManager ISensorBoardManager component
	 * @return the component LightSensor
	 */
	public static ISensorBoardComponent getLightSensor(ISensorBoardManager sensorBoardManager) {
		if (lightSensor == null) {
			lightSensor = new LightSensor(sensorBoardManager);
		}
		return lightSensor;
	}

	/**
	 * Getter of the component AccelerometerSensor
	 * @param sensorBoardManager ISensorBoardManager component
	 * @return the component AccelerometerSensor
	 */
	public static ISensorBoardComponent getAcceleratorSensor(ISensorBoardManager sensorBoardManager) {
		if (acceleratorSensor == null) {
			acceleratorSensor = new AccelerometerSensor(sensorBoardManager);
		}
		return acceleratorSensor;
	}
	
	/**
	 * Getter of the component LedActuator
	 * @param sensorBoardManager ISensorBoardManager component
	 * @return the component LedActuator
	 */
	public static ISensorBoardComponent getLedActuator(ISensorBoardManager sensorBoardManager) {
		if (ledActuator == null) {
			ledActuator = new LedOut(sensorBoardManager);
		}
		return ledActuator;
	}
	
	/**
	 * Getter of the component SwitchInput
	 * @param sensorBoardManager ISensorBoardManager component
	 * @return the component SwitchInput
	 */
	public static ISensorBoardComponent getSwitchInput(ISensorBoardManager sensorBoardManager) {
		if (switchInput == null) {
			switchInput = new SwitchInput(sensorBoardManager);
		}
		return switchInput;
	}

	/**
	 * Getter of the component SwitchInput
	 * @param sensorBoardManager ISensorBoardManager component
	 * @return the component SwitchInput
	 */
	public static ISensorBoardComponent getFlashManager(ISensorBoardManager sensorBoardManager) {
		if (flashManager == null) {
			flashManager = new Flash(sensorBoardManager);
		}
		return flashManager;
	}

	public static ISensorBoardComponent getBatteryManager(ISensorBoardManager sensorBoardManager) {
		if (batteryManager == null) {
			batteryManager = new Battery(sensorBoardManager);
		}
		return batteryManager;
	}

}
